package com.joymart.qualification.service;

import com.joymart.common.abstraction.StatusService;
import com.joymart.common.error.handling.JoymartBusinessException;
import com.joymart.common.model.ApprovalStatus;
import com.joymart.common.model.Range;
import com.joymart.common.system.IdGenerator;
import com.joymart.common.utils.DatetimeUtils;
import com.joymart.common.utils.SecurityUtils;
import com.joymart.compute.service.VitalityPointService;
import com.joymart.prepaid.wallet.model.PrepaidWallet;
import com.joymart.prepaid.wallet.service.PrepaidWalletService;
import com.joymart.qualification.model.AdvanceEvaluationRecord;
import com.joymart.qualification.model.QualificationApplication;
import com.joymart.qualification.model.ShopEvaluation;
import com.joymart.user.model.BusinessRole;
import com.joymart.user.model.CachedUser;
import com.joymart.user.model.User;
import com.joymart.user.repo.UserRepository;
import com.joymart.user.service.UserCacheManager;
import com.joymart.user.service.UserService;
import com.joymart.wechat.service.WechatOpenPlatformService;
import lombok.Data;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.*;
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
import org.springframework.data.relational.core.query.Criteria;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.text.DateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static com.joymart.common.utils.CollectionUtils.asList;
import static org.springframework.data.relational.core.query.Criteria.where;
import static org.springframework.data.relational.core.query.Query.query;

@Service
@Transactional
public class ApplicationService extends StatusService<QualificationApplication, ApprovalStatus> {

    @Autowired
    private IdGenerator idGenerator;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private JdbcAggregateTemplate jdbcAggregateTemplate;
    @Autowired
    private UserCacheManager userCacheManager;
    @Autowired
    private UserService userService;
    @Autowired
    private ShopEvaluationService shopEvaluationService;
    @Autowired
    private AdvanceEvaluationPersistingService advanceEvaluationPersistingService;
    @Autowired
    private VitalityPointService vitalityPointService;
    @Value("${wechat.qualificationApplicationTemplateId}")
    private String qualificationApplicationTemplateId;
    @Autowired
    private WechatOpenPlatformService wechatOpenPlatformService;

    public QualificationApplication createApplication(QualificationApplication application) {
        CachedUser user = userCacheManager.get(SecurityUtils.getCurrentUserId());

        if(existPending(user.getId(), application.getTargetRole())){
            throw new JoymartBusinessException("有正在进行的申请，请勿重复申请");
        }

        if(user.getBusinessRoles().contains(application.getTargetRole())){
            throw new JoymartBusinessException("您已具备资格，请勿重复申请");
        }

        //店铺审核活力点数
        if(application.getTargetRole() == BusinessRole.AG_SHOP){
            ShopEvaluation shopEvaluation = shopEvaluationService.evaluateShop(user.getId());

            if(!shopEvaluation.isQualified()){
                throw new JoymartBusinessException("积分尚不满足");
            }
        }else{ //其他审核评估结果
            AdvanceEvaluationRecord evaluationResult =
                    Optional.ofNullable(application.getMeta().getString("evaluationId"))
                        .map(advanceEvaluationPersistingService::getEvaluationResultById)
                        .get();
            if(evaluationResult == null || evaluationResult.getTargetRole() != application.getTargetRole() || !evaluationResult.isPassed() || !evaluationResult.getUserId().equals(user.getId())){
                throw new JoymartBusinessException("根据评估结果，您暂时未达标");
            }
            // 25天以前的评估不能作为申请依据，防止跨整月的情况
            if(Duration.between(evaluationResult.getCreatedAt(), DatetimeUtils.now()).toDays() > 25){
                throw new JoymartBusinessException("很抱歉，您没有及时在评估生成后申请。评估时效已过。");
            }
        }

        application.setId(idGenerator.next());
        application.setApplicantId(SecurityUtils.getCurrentUserId());
        application.setCreatedAt(DatetimeUtils.now());
        this.modifyStatus(application, ApprovalStatus.PENDING);
        jdbcAggregateTemplate.insert(application);
        return application;
    }



    public void rejectApplication(String applicationId, String comment) {
        QualificationApplication application = jdbcAggregateTemplate.findById(applicationId, QualificationApplication.class);
        this.checkStatus(application, ApprovalStatus.PENDING);
        application.setDecidedAt(DatetimeUtils.now());
        application.setDecidedBy(SecurityUtils.getCurrentUserId());
        application.setComment(comment);
        this.modifyStatus(application, ApprovalStatus.REJECTED);
        jdbcAggregateTemplate.save(application);
        Map<String, Object> subMsgData =
                Map.of("time2", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(application.getCreatedAt()),
                        "thing3", "资格申请被驳回(%s)".formatted(comment));
        wechatOpenPlatformService.sendSubscribeMessage(application.getApplicantId(), qualificationApplicationTemplateId,subMsgData ,null);
    }

    public void approveApplication(String applicationId) {

        QualificationApplication application = jdbcAggregateTemplate.findById(applicationId, QualificationApplication.class);
        this.checkStatus(application, ApprovalStatus.PENDING);
        checkNotTimeoutApplication(application);
        checkCurrentRole(application.getApplicantId(), application.getTargetRole());
        application.setDecidedAt(DatetimeUtils.now());
        application.setDecidedBy(SecurityUtils.getCurrentUserId());
        this.modifyStatus(application, ApprovalStatus.APPROVED);
        jdbcAggregateTemplate.save(application);

        //发送通知
        Map<String, Object> subMsgData =
                Map.of("time2", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(application.getCreatedAt()),
                        "thing3", "%s申请已通过".formatted(application.getTargetRole().getText()));
        wechatOpenPlatformService.sendSubscribeMessage(application.getApplicantId(), qualificationApplicationTemplateId,subMsgData ,null);

        //处理后续逻辑
        switch (application.getTargetRole()){
            case AG_SHOP -> businessAfterShopApproval(application);
            case AG_WHS-> businessAfterWhsApproval(application);
            case AG_AGENT -> businessAfterAgentApproval(application);
            case MANAGER -> businessAfterManagerApproval(application);
        }
    }

    /**
     *  加上时间判断 太久了之前的申请就不能通过了 跨年的经理申请会影响年度审核，所以判定更严格
     */
    private void checkNotTimeoutApplication(QualificationApplication application) {
        if(application.getTargetRole() == BusinessRole.MANAGER){
            LocalDateTime applicationCreated = application.getCreatedAt();
            LocalDateTime now = DatetimeUtils.now();
            // 每年1月5日前提交的经理申请，必须在本年 1月1日 至  1月4日前完成审核
            if(applicationCreated.getDayOfYear() <5 && now.getDayOfYear() > 4){
                throw new JoymartBusinessException("申请时效已过， 请手动驳回");
            }
        }
        // 只能通过15天以内的申请，审核人员必须及时查看并审核
        if(Duration.between(application.getCreatedAt(), DatetimeUtils.now()).toDays() > 15){
            throw new JoymartBusinessException("申请时效已过， 请手动驳回");
        }


    }

    private void businessAfterManagerApproval(QualificationApplication application) {
        CachedUser user = userCacheManager.get(application.getApplicantId());
        userService.modifyHighestRole(user.getUser(), BusinessRole.MANAGER);
    }

    private void businessAfterAgentApproval(QualificationApplication application) {
        CachedUser user = userCacheManager.get(application.getApplicantId());
        userService.modifyHighestRole(user.getUser(), BusinessRole.AG_AGENT);

        //如果下游有银代理，直接升级将评估人升级成金代理
        CachedUser downstreamAgent = userCacheManager.downwardsSearchUntil(user, u->u.getBusinessRoles().contains(BusinessRole.AG_AGENT));
        if(downstreamAgent != null){
            userService.modifyHighestRole(user.getUser(), BusinessRole.AU_AGENT);
        }

        //如果上级还不是金代理，将其变为金代理
        CachedUser upperAgent = userCacheManager.upwardSearchUntil(user, u -> u.getBusinessRoles().contains(BusinessRole.AG_AGENT));
        if( upperAgent!=null && !upperAgent.getBusinessRoles().contains(BusinessRole.AU_AGENT)){
            userService.modifyHighestRole(upperAgent.getUser(), BusinessRole.AU_AGENT);
        }
    }

    private void businessAfterWhsApproval(QualificationApplication application) {
        CachedUser user = userCacheManager.get(application.getApplicantId());
        userService.modifyHighestRole(user.getUser(), BusinessRole.AG_WHS);

        // 如果下游有批发商， 直接将评估人升级成金批发
        CachedUser downstreamWhs = userCacheManager.downwardsSearchUntil(user, u -> u.getBusinessRoles().contains(BusinessRole.AG_WHS));
        if(downstreamWhs!=null){
            userService.modifyHighestRole(user.getUser(), BusinessRole.AU_WHS);
        }

        //如果上级还不是金批发，将其变为金批发
        CachedUser upperWhs = userCacheManager.upwardSearchUntil(user, u -> u.getBusinessRoles().contains(BusinessRole.AG_WHS));
        if( upperWhs!=null && !upperWhs.getBusinessRoles().contains(BusinessRole.AU_WHS)){
            userService.modifyHighestRole(upperWhs.getUser(), BusinessRole.AU_WHS);
        }
    }

    private void businessAfterShopApproval(QualificationApplication application) {
        CachedUser user = userCacheManager.get(application.getApplicantId());
        userService.modifyHighestRole(user.getUser(), BusinessRole.AG_SHOP);


        //如果下游有店铺，直接升级成金店铺
        CachedUser downstreamShop = userCacheManager.downwardsSearchUntil(user, u -> u.getBusinessRoles().contains(BusinessRole.AG_SHOP));
        if(downstreamShop!=null){
            userService.modifyHighestRole(user.getUser(), BusinessRole.AU_SHOP);
        }

        //如果上级还不是金店铺，将其变为金店铺
        CachedUser upperShop = userCacheManager.upwardSearchUntil(user, u -> u.getBusinessRoles().contains(BusinessRole.AG_SHOP));
        if(upperShop!=null && !upperShop.getBusinessRoles().contains(BusinessRole.AU_SHOP)){
            userService.modifyHighestRole(upperShop.getUser(), BusinessRole.AU_SHOP);
        }

        //将贡献的活力点数无效化
        vitalityPointService.invalidateVitalityPoints(user.getId());


    }



    private void checkCurrentRole(String applicantId, BusinessRole targetRole) {
        if (userCacheManager.get(applicantId).getBusinessRoles().contains(targetRole)) {
            throw new JoymartBusinessException("申请者已具备相应资格， 请手动驳回");
        }
    }



    public Page<QualificationApplicationDto> searchApplication(BusinessRole targetRole,
                                                               ApprovalStatus targetStatus,
                                                               String keyword,
                                                               Range range,
                                                               Pageable pageable) {

        Criteria criteria =  where("createdAt").between(range.getStart(), range.getEnd());
        if(StringUtils.hasText(keyword)){
            List<String> userIds = userRepository.findIdsByNicknameContains(keyword);
            criteria =  criteria.and("applicantId").in(userIds);
        }
        if(targetStatus!=null) {
            criteria = criteria.and(where("status").is(targetStatus));
        }
        if(targetRole!=null) {
            criteria = criteria.and(where("targetRole").is(targetRole));
        }

        long count = jdbcAggregateTemplate.count(query(criteria), QualificationApplication.class);
        if(count == 0l){
            return Page.empty();
        }
        List<QualificationApplication> content = asList(jdbcAggregateTemplate.findAll(query(criteria).limit(pageable.getPageSize()).offset(pageable.getOffset())
                .sort(Sort.by(Sort.Direction.DESC, "createdAt")), QualificationApplication.class));
        return new PageImpl<>(content, pageable, count).map(this::toDto);
    }

    public QualificationApplication findById(String id) {
        return jdbcAggregateTemplate.findById(id, QualificationApplication.class);
    }


    @Data
    public static class QualificationApplicationDto {

        private String id;
        //申请人ID
        private User applicant;
        private BusinessRole targetRole;
        private JSONObject meta;
        private String comment;
        //签名图片地址
        private String signatureUrl;
        //协议ID
        private String protocolId;
        //审批状态
        private ApprovalStatus status;
        private LocalDateTime createdAt;
        //审批人ID
        private User decidedBy;
        // 审批时间
        private LocalDateTime decidedAt;
    }

    public QualificationApplicationDto toDto(QualificationApplication source) {
        QualificationApplicationDto dto = new QualificationApplicationDto();
        BeanUtils.copyProperties(source,dto );
        dto.setApplicant(userCacheManager.get(source.getApplicantId()).getUser());
        dto.setDecidedBy(Optional.ofNullable(source.getDecidedBy()).map(userCacheManager::get).map(CachedUser::getUser).orElse(null));
        return dto;
    }



    public boolean existPending(String applicantId, BusinessRole targetRole) {
        Criteria criteria =  where("applicantId").is(applicantId)
                .and("targetRole").is(targetRole)
                .and("status").is(ApprovalStatus.PENDING);
        return jdbcAggregateTemplate.exists(query(criteria), QualificationApplication.class);
    }


}
